#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#康威生命游戏（二维元胞自动机）模拟

#特性：
#支持模拟状态数为2的二维元胞自动机
#支持摩尔邻域和冯诺依曼邻域
#支持动态区域大小
#支持动态空间释放（即把空的位置释放，仅显示坐标原点到当前存在的存活方格）

#待优化项：
#使用collections模块的defaultdict类型代替dict，从而避免get语句的使用
#将display()模块中q和p的赋值放在一个循环体中，而非两个列表生成式，从而避免多余的一次循环

from copy import deepcopy
from os import system
import time

#初始形状
start = '''
.##
##.
..#
'''

#自动机参数
B = (3, )
S = (2, 3)
#邻域类型 True为摩尔邻域 False为冯诺依曼邻域
neighbourhood = True

#自动运行
auto = False
#迭代步数（仅当auto = True时生效）
gen = 20
#是否清屏
cls = False
#清屏时每个步骤显示时间（秒）（仅当auto = True时生效）
wait = 1

#形状
shape = ('　', '▇▇', '─┼', '──', ' │')
#shape = (' ', '#', '┼', '─', '│')
#显示坐标轴
axis = True
#坐标轴上显示数字
numaxis =True
#显示步数
showgen = True

a = {}
def init():
    i = 0
    for line in reversed(start.split()):
        i += 1
        a[i] = {}
        p = 0
        for row in line:
            p += 1
            if row == '*' or row == '#':
                a[i][p] = 1
            else:
                #a[i][p] = 0
                pass

def gen_next():
    global a
    b = deepcopy(a)
    p = min([min(a.get(line, {}).keys()) - 1 for line in range(min(a.keys()), max(a.keys()) + 1)])
    q = max([max(a.get(line, {}).keys()) + 2 for line in range(min(a.keys()), max(a.keys()) + 1)])
    for line in range(min(a.keys()) - 1, max(a.keys()) + 2):
        for row in range(p, q):
            round = a.get(line, {}).get(row-1, 0)
            round += a.get(line, {}).get(row+1, 0)
            round += a.get(line-1, {}).get(row, 0)
            round += a.get(line+1, {}).get(row, 0)
            if neighbourhood:
                round += a.get(line-1, {}).get(row-1, 0)
                round += a.get(line-1, {}).get(row+1, 0)
                round += a.get(line+1, {}).get(row-1, 0)
                round += a.get(line+1, {}).get(row+1, 0)
            if round in B:
                if line not in b.keys():
                    b[line] = {}
                b[line][row] = 1
            if round not in S and a.get(line, {}).get(row, 0) == 1:
                #b[line][row] = 0
                del b[line][row]
        if b.get(line) == {}:
            del b[line]
    a = deepcopy(b)

def display():
    p = min([min(a.get(line, {}).keys()) for line in range(min(a.keys()), max(a.keys()) + 1)] + [0])
    q = max([max(a.get(line, {}).keys()) + 1 for line in range(min(a.keys()), max(a.keys()) + 1)] + [1])
    for line in range(max(max(a.keys()), 0), min(min(a.keys()) - 1, -1), -1):
        for row in range(p, q):
            if axis:
                if line == 0 and row == 0 and a.get(line, {}).get(row, 0) == 0:
                    if numaxis:
                        print(' ', end='')
                        print(0, end='')
                    else:
                        print(shape[2], end='')
                elif line == 0 and a.get(line, {}).get(row, 0) == 0:
                    if numaxis:
                        if row > 0:
                            print(' ', end='')
                        print(row, end='')
                    else:
                        print(shape[3], end='')
                elif row == 0 and a.get(line, {}).get(row, 0) == 0:
                    if numaxis:
                        if line > 0:
                            print(' ', end='')
                        print(line, end='')
                    else:
                        print(shape[4], end='')
                else:
                    if a.get(line, {}).get(row, 0) == 1:
                        print(shape[1], end='')
                    else:
                        print(shape[0], end='')
            else:
                if a.get(line, {}).get(row, 0) == 1:
                    print(shape[1], end='')
                else:
                    print(shape[0], end='')
        print('')
    print('')

init()
display()
g = 0
if auto:
    while g < gen:
        g += 1
        gen_next()
        if cls:
            time.sleep(wait)
            system("clear")
        if showgen:
            print('Generation: %d' % g)
        display()
else:
    while True:
        g += 1
        gen_next()
        if cls:
            system("clear")
        if showgen:
            print('Generation: %d' % g)
        display()
        if input() != '':
            exit()